{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7e3a1d9e-3a48-41ff-a2b7-2dbcdb82c520",
   "metadata": {},
   "source": [
    "# Other widget libraries\n",
    "\n",
    "We would have loved to show you everything the Jupyter Widgets ecosystem has to offer today, but we are blessed to have such an active community of widget creators and unfortunately can't fit all widgets in a single session, no matter how long. \n",
    "\n",
    "This notebook lists some of the widget libraries we wanted to demo but did not have enough time to include in the session. Enjoy!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6bbc79d5-86b4-4b2b-b924-e458375e090a",
   "metadata": {},
   "source": [
    "# ipyleaflet: Interactive maps\n",
    "\n",
    "## A Jupyter - LeafletJS bridge\n",
    "\n",
    "## https://github.com/jupyter-widgets/ipyleaflet\n",
    "\n",
    "\n",
    "ipyleaflet is a jupyter interactive widget library which provides interactive maps to the Jupyter notebook.\n",
    "\n",
    "- MIT Licensed\n",
    "\n",
    "**Installation:**\n",
    "\n",
    "```bash\n",
    "conda install -c conda-forge ipyleaflet\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c77c85c9-6d99-475c-a9a2-e2c190ba4122",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import Text, HTML, HBox\n",
    "from ipyleaflet import GeoJSON, WidgetControl, Map \n",
    "import json"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54c3506c-2ac0-4319-bfcc-e017f0885295",
   "metadata": {},
   "outputs": [],
   "source": [
    "m = Map(center = (43,-100), zoom = 4)\n",
    "\n",
    "geo_json_data = json.load(open('us-states-density-colored.json'))\n",
    "geojson = GeoJSON(data=geo_json_data, hover_style={'color': 'black', 'dashArray': '5, 5', 'weight': 2})\n",
    "m.add_layer(geojson)\n",
    "\n",
    "html = HTML('''\n",
    "    <h4>US population density</h4>\n",
    "    Hover over a state\n",
    "''')\n",
    "html.layout.margin = '0px 20px 20px 20px'\n",
    "control = WidgetControl(widget=html, position='topright')\n",
    "m.add_control(control)\n",
    "\n",
    "def update_html(properties, **kwargs):\n",
    "    html.value = '''\n",
    "        <h4>US population density</h4>\n",
    "        <h2><b>{}</b></h2>\n",
    "        {} people / mi^2\n",
    "    '''.format(properties['name'], properties['density'])\n",
    "\n",
    "geojson.on_hover(update_html)\n",
    "\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bfcd179-0463-4b07-9bce-f7ba298ed3de",
   "metadata": {},
   "source": [
    "# pythreejs: 3D rendering in the browser \n",
    "\n",
    "## A Jupyter - threejs bridge\n",
    "\n",
    "## https://github.com/jupyter-widgets/pythreejs\n",
    "\n",
    "\n",
    "Pythreejs is a jupyter interactive widget bringing fast WebGL 3d visualization to the Jupyter notebook.\n",
    "\n",
    "- Originally authored by Jason Grout, currently maintained by Vidar Tonaas Fauske\n",
    "- BSD Licensed\n",
    "\n",
    "Pythreejs is *not* a 3d plotting library, it only exposes the threejs scene objects to the Jupyter kernel.\n",
    "\n",
    "**Installation:**\n",
    "\n",
    "```bash\n",
    "conda install -c conda-forge pythreejs\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "989097a4-302f-4092-a784-814282b5c366",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pythreejs import *\n",
    "import numpy as np\n",
    "from IPython.display import display\n",
    "from ipywidgets import HTML, Text, Output, VBox\n",
    "from traitlets import link, dlink"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "07bb1212-d30f-4b22-a1e9-75ba63c449cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Generate surface data:\n",
    "view_width = 600\n",
    "view_height = 400\n",
    "nx, ny = (20, 20)\n",
    "xmax=1\n",
    "x = np.linspace(-xmax, xmax, nx)\n",
    "y = np.linspace(-xmax, xmax, ny)\n",
    "xx, yy = np.meshgrid(x, y)\n",
    "z = xx ** 2 - yy ** 2\n",
    "#z[6,1] = float('nan')\n",
    "\n",
    "\n",
    "# Generate scene objects from data:\n",
    "surf_g = SurfaceGeometry(z=list(z[::-1].flat), \n",
    "                         width=2 * xmax,\n",
    "                         height=2 * xmax,\n",
    "                         width_segments=nx - 1,\n",
    "                         height_segments=ny - 1)\n",
    "\n",
    "surf = Mesh(geometry=surf_g,\n",
    "            material=MeshLambertMaterial(map=height_texture(z[::-1], 'YlGnBu_r')))\n",
    "\n",
    "surfgrid = SurfaceGrid(geometry=surf_g, material=LineBasicMaterial(color='black'),\n",
    "                       position=[0, 0, 1e-2])  # Avoid overlap by lifting grid slightly\n",
    "\n",
    "# Set up picking bojects:\n",
    "hover_point = Mesh(geometry=SphereGeometry(radius=0.05),\n",
    "                   material=MeshLambertMaterial(color='green'))\n",
    "\n",
    "click_picker = Picker(controlling=surf, event='dblclick')\n",
    "hover_picker = Picker(controlling=surf, event='mousemove')\n",
    "\n",
    "# Set up scene:\n",
    "key_light = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.4)\n",
    "c = PerspectiveCamera(position=[0, 3, 3], up=[0, 0, 1], aspect=view_width / view_height,\n",
    "                      children=[key_light])\n",
    "\n",
    "scene = Scene(children=[surf, c, surfgrid, hover_point, AmbientLight(intensity=0.8)])\n",
    "\n",
    "renderer = Renderer(camera=c, scene=scene,\n",
    "                    width=view_width, height=view_height,\n",
    "                    controls=[OrbitControls(controlling=c), click_picker, hover_picker])\n",
    "\n",
    "\n",
    "# Set up picking responses:\n",
    "# Add a new marker when double-clicking:\n",
    "out = Output()\n",
    "def f(change):\n",
    "    value = change['new']\n",
    "    with out:\n",
    "        print('Clicked on %s' % (value,))\n",
    "    point = Mesh(geometry=SphereGeometry(radius=0.05), \n",
    "                 material=MeshLambertMaterial(color='hotpink'),\n",
    "                 position=value)\n",
    "    scene.add(point)\n",
    "\n",
    "click_picker.observe(f, names=['point'])\n",
    "\n",
    "# Have marker follow picker point:\n",
    "link((hover_point, 'position'), (hover_picker, 'point'))\n",
    "\n",
    "# Show picker point coordinates as a label:\n",
    "h = HTML()\n",
    "def g(change):\n",
    "    h.value = 'Green point at (%.3f, %.3f, %.3f)' % tuple(change['new'])\n",
    "    h.value += '  Double-click to add marker'\n",
    "g({'new': hover_point.position})\n",
    "hover_picker.observe(g, names=['point'])\n",
    "\n",
    "display(VBox([h, renderer, out]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "228aa568-3b3b-4901-9700-b6a865e474a1",
   "metadata": {},
   "source": [
    "# bqplot: complex interactive visualizations\n",
    "\n",
    "## https://github.com/bloomberg/bqplot\n",
    "\n",
    "## A Jupyter - d3.js bridge\n",
    "\n",
    "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n",
    "\n",
    "- Apache Licensed\n",
    "\n",
    "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n",
    "\n",
    "bqplot provides both\n",
    "-\thigh-level plotting procedures with relevant defaults for common chart types,\n",
    "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n",
    "\n",
    "**Installation:**\n",
    "\n",
    "```bash\n",
    "conda install -c conda-forge bqplot\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e406ea84-67fe-4137-9b26-cf4cbdb4e751",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import bqplot as bq"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "625bd9df-8661-4267-aa34-3c758e04be21",
   "metadata": {},
   "outputs": [],
   "source": [
    "xs = bq.LinearScale()\n",
    "ys = bq.LinearScale()\n",
    "x = np.arange(100)\n",
    "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n",
    "\n",
    "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n",
    "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n",
    "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n",
    "\n",
    "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n",
    "display(fig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94ac959d-76d1-4712-914c-bcb931d04e93",
   "metadata": {},
   "outputs": [],
   "source": [
    "# update data of the line mark\n",
    "line.y = np.cumsum(np.random.randn(2, 100), axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ce97fcb-e621-4b0e-b826-d49c04146f51",
   "metadata": {},
   "source": [
    "# ipympl: The Matplotlib Jupyter Widget Backend\n",
    "\n",
    "## https://matplotlib.org/ipympl/\n",
    "\n",
    "\n",
    "Enabling interaction with matplotlib charts in the Jupyter notebook and JupyterLab\n",
    "\n",
    "- BSD-3-Clause\n",
    "\n",
    "**Installation:**\n",
    "\n",
    "```bash\n",
    "conda install -c conda-forge ipympl\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91a33e30-803d-4945-8129-2c37f30a1d09",
   "metadata": {},
   "source": [
    "Enabling the `ipympl` (sometimes written `widget`) backend. ipympl can be install via pip or conda."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b157ee7-4008-492d-8045-f93b747af703",
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib ipympl"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "152cba47-06f1-4896-b15a-b3ed960cafd3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from ipywidgets import VBox, FloatSlider"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc9dca28-883c-4286-af3d-a17081b089d6",
   "metadata": {},
   "source": [
    "When using the `widget` backend from ipympl, `fig.canvas` is a proper Jupyter interactive widget, which can be embedded in Layout classes like `HBox` and `VBox`.\n",
    "\n",
    "One can bind figure attributes to other widget values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9db5b3e0-317c-4b79-bb5c-36786d02895a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "with plt.ioff():\n",
    "    fig, ax = plt.subplots()\n",
    "\n",
    "x1 = np.linspace(0, 20, 500)\n",
    "\n",
    "slider = FloatSlider(\n",
    "    value=1.0,\n",
    "    min=0.02,\n",
    "    max=2.0\n",
    ")\n",
    "\n",
    "lines = plt.plot(x1, np.sin(slider.value  * x1))\n",
    "\n",
    "def update_lines(change):\n",
    "    lines[0].set_data(x1, np.sin(change.new * x1))\n",
    "    fig.canvas.draw()\n",
    "\n",
    "slider.observe(update_lines, names='value')\n",
    "\n",
    "VBox([slider, fig.canvas])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24389d91-db96-4591-a279-9dde81b9c8ef",
   "metadata": {},
   "source": [
    "# ipytree: Interactive tree view based on ipywidgets\n",
    "\n",
    "## https://github.com/QuantStack/ipytree/\n",
    "\n",
    "\n",
    "ipytree is a jupyter interactive widget library which provides a tree widget to the Jupyter notebook.\n",
    "\n",
    "- MIT Licensed\n",
    "\n",
    "**Installation:**\n",
    "\n",
    "```bash\n",
    "conda install -c conda-forge ipytree\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fa20469b-b9b6-46bc-99f0-e85c313db971",
   "metadata": {},
   "source": [
    "## Create a tree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c3b13d81-455d-438c-a843-f31421db0fc1",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ipywidgets import Text, link\n",
    "from ipytree import Tree, Node"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5461f21f-e96e-4877-8f4c-bc1bc5f572e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "tree = Tree()\n",
    "tree.add_node(Node('node1'))\n",
    "\n",
    "node2 = Node('node2')\n",
    "tree.add_node(node2)\n",
    "\n",
    "tree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6059b01a-8c08-492a-834b-450905e5c3dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "node3 = Node('node3', disabled=True)\n",
    "node4 = Node('node4')\n",
    "node5 = Node('node5', [Node('1'), Node('2')])\n",
    "node2.add_node(node3)\n",
    "node2.add_node(node4)\n",
    "node2.add_node(node5)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "widgets-tutorial",
   "language": "python",
   "name": "widgets-tutorial"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "state": {},
    "version_major": 2,
    "version_minor": 0
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
